﻿using S7.Net.Types;
using S7.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PLCTest.Util
{
    public class PlcConnectionS7
    {

        private readonly ILogUtil _LogUtil;
        private Plc _Plc;
        private bool isConnected { get; set; }
        public bool IsConnected { get { return _Plc == null ? false : _Plc.IsConnected; } }
        //public bool IsConnected { get; set; } = false;
        public string IP { get; set; }
        public PlcConnectionS7(CpuType cpuType, string ip, short rack, short slot, ILogUtil logUtil)
        {
            //slot:PLC的CPU插槽，通常S7300-S7400为2,S7-1200和S7-1500为0。如果您使用外部以太网卡，则必须相应地进行设置。
            //rack:通常是0，但请检查Step7或TIA portal的硬件配置
            _Plc = new Plc(cpuType, ip, rack, slot);
            IP = ip;
            _LogUtil = logUtil;
            _Plc.ReadTimeout = 800;
            _Plc.WriteTimeout = 800;
        }

        public async Task<bool> ConnectAsync()
        {
            try
            {
                isConnected = await IPService.PingAsync(_Plc.IP);
                if (isConnected)
                    await _Plc.OpenAsync();//连接
            }
            catch (Exception ex)
            {
                _LogUtil.Error($"S7Plc连接发生异常ConnectAsync，IP：{_Plc.IP}");
            }
            return isConnected;
        }
        public bool DisConnect()
        {
            try
            {
                _Plc.Close();
            }
            catch (Exception ex)
            {
                _LogUtil.Error($"S7Plc连接发送异常DisConnect，IP：{IP}");
            }
            return _Plc == null || _Plc.IsConnected;
        }



        public async Task<object> ReadTypeValue(string point, string type, int start = 2)
        {

            try
            {
                switch (type)
                {
                    case "bool":
                        return await ReadBool(point);
                    case "string":
                        return await ReadString(point, start);
                }
            }
            catch (Exception)
            {
                return null;
            }
            return null;

        }


        public async Task<bool> ReadBool(string point)
        {
            var value = await _Plc.ReadAsync(point);
            return value.ToBool();
        }

        public async Task<string> ReadString(string point, int start)
        {
            byte[] value = (byte[])await _Plc.ReadAsync(point);
            int length = StringExt.GetSIntAt(value, 1);
            var code = StringExt.GetCharsAt(value, start, length);
            return code;
        }

        public async Task<int> ReadInt16(string point)
        {
            var value = await _Plc.ReadAsync(point);
            return value.ToInt32();
        }

        public async Task<byte[]> ReadByte(string point)
        {
            byte[] value = (byte[])await _Plc.ReadAsync(point);
            return value;
        }

        public async Task<object> ReadPlcPoint(string point)
        {
            var value = await _Plc.ReadAsync(point);
            return value;
        }

        public async Task<byte[]> ReadDbAsync(int DB, int start, int length)
        {
            //bool isOpen = await ConnectAsync();
            if (!IsConnected)
            {
                return null;
            }
            try
            {

                byte[] bytes = await _Plc.ReadBytesAsync(DataType.DataBlock, DB, start, length);
                var bytesStr = "";
                foreach (var byteItem in bytes)
                {
                    bytesStr += byteItem.ToString() + ":";
                }
                bytesStr = bytesStr.TrimEnd(':');
                _LogUtil.Debug($"读取PLC数据：【{bytesStr}】");
                return bytes;
            }
            catch (Exception ex)
            {
                _LogUtil.Error($"S7Plc读报文发生异常ReadDbAsync，IP：{_Plc.IP}，DB：{DB}，start：{start}，length：{length}, ex={ex.Message}");
                isConnected = false;
            }
            return null;
        }
        public async Task<bool> WriteDbAsync(int DB, int start, byte[] bytes)
        {
            //bool isOpen = await ConnectAsync();
            if (!IsConnected)
            {
                return false;
            }
            try
            {
                await _Plc.WriteBytesAsync(DataType.DataBlock, DB, start, bytes);

                return true;
            }
            catch (Exception ex)
            {
                _LogUtil.Error($"S7Plc写报文发生异常WriteDbAsync，IP：{_Plc.IP}，DB：{DB}，start：{start}");
                isConnected = false;
            }
            return false;
        }

        /// <summary>
        /// 写一个点位
        /// </summary>
        /// <param name="point"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<bool> WritePointAsync(string point, object value)
        {
            try
            {
                await _Plc.WriteAsync(point, value);
                return true;
            }
            catch (Exception ex)
            {
                _LogUtil.Error($"S7Plc写报文发生异常WritePointAsync，IP：{_Plc.IP}，DB：{point}，value：{value}");
            }
            return false;

        }

        public async Task<bool> WriteDbBitAsync(int DB, int start, int bitAdr, bool value)
        {
            if (!IsConnected)
            {
                return false;
            }
            try
            {
                await _Plc.WriteBitAsync(DataType.DataBlock, DB, start, bitAdr, value);
                return true;
            }
            catch (Exception ex)
            {
                _LogUtil.Error($"S7Plc写报文发生异常WriteDbBitAsync，IP：{_Plc.IP}，DB：{DB}，start：{start}");
            }
            return false;
        }


    }
}
